{%mainunit bitcoin_p2p.pas}

{$IFDEF INTERFACE}
type
  { TMsgTx This represents a tx message. It maintains arrays of
    inputs and outputs (which contain elements of TTxIn and TTxOut). The
    Parse() method will create all these sub-objects, and let them parse
    themselves }
  TMsgTx = class(TMsg)
    Version: DWord;
    InputCount: QWord;
    InputList: array of TTxIn;
    OutputCount: QWord;
    OutputList: array of TTxOut;
    LockTime: DWord;
    destructor Destroy; override;
    class function GetCommand: Tp2pCommand; override;
    procedure ParseAndProcess; override;
    function Serialize: String; override;
    function SerializeWithoutHeader: String;
  end;

{$ENDIF}
{$IFDEF IMPLEMENTATION}

destructor TMsgTx.Destroy;
var
  I : Integer;
begin
  for I := 0 to InputCount-1 do
    InputList[I].Free;
  for I := 0 to OutputCount-1 do
    InputList[I].Free;
  SetLength(InputList, 0);
  SetLength(OutputList, 0);
  inherited Destroy;
end;

class function TMsgTx.GetCommand: Tp2pCommand;
begin
  Result := 'tx'#0#0#0#0#0#0#0#0#0#0;
end;

procedure TMsgTx.ParseAndProcess;
var
  I     : Integer;
  Cnt   : Integer;
begin
  Version := ReadDWord;

  Cnt := ReadVarInt;
  SetLength(InputList, Cnt);
  InputCount := 0;
  for I :=  0 to InputCount-1 do begin
    InputList[I] := TTxIn.Create(FPeer, FReceiveData);
    // since Parse can throw exceptions we always need to know how many
    // items exactly there are in the list to free again in the destructor.
    // So we increment it by one after each create (and before the parse).
    Inc(InputCount);
    InputList[I].ParseAndProcess;
  end;

  Cnt := ReadVarInt;
  SetLength(OutputList, Cnt);
  OutputCount := 0;
  for I :=  0 to OutputCount-1 do begin
    OutputList[I] := TTxOut.Create(FPeer, FReceiveData);
    Inc(OutputCount);
    OutputList[I].ParseAndProcess;
  end;

  LockTime := ReadDWord;

  {$note remove this logging again once it all works}
  log('parsed tx: inputs: %d, outputs %d', [InputCount, OutputCount]);
end;

function TMsgTx.Serialize: String;
begin
  Result := WrapHeader(SerializeWithoutHeader);
end;

function TMsgTx.SerializeWithoutHeader: String;
var
  I : Integer;
begin
  FSendData := TStringStream.Create('');
  WriteDWord(Version);
  WriteVarInt(InputCount);
  for I := 0 to InputCount-1 do
    InputList[I].SerializeToStream(FSendData);
  for I := 0 to OutputCount-1 do
    OutputList[I].SerializeToStream(FSendData);
  WriteDWord(LockTime);
  Result := FSendData.DataString;
  FSendData.Free;
end;

{$ENDIF}
